1 // ----------------------------------------------------------------------------
2 // <copyright file=
"PhotonView.cs" company="Exit Games GmbH">
3 // PhotonNetwork Framework
for Unity - Copyright (C) 2011 Exit Games GmbH
4 // </copyright>
5 // <summary>
6 //
7 // </summary>
8 // <author>developer@exitgames.com</author>
9 // ----------------------------------------------------------------------------

10
11 using
System;
12 using
UnityEngine;
13 using
System.Reflection;
14 using
System.Collections.Generic;
15 using
ExitGames.Client.Photon;
16
17 #
if UNITY_EDITOR
18 using
UnityEditor;
19 #endif

20
21
22 public
enum ViewSynchronization { Off, ReliableDeltaCompressed, Unreliable, UnreliableOnChange }
23 public
enum OnSerializeTransform { OnlyPosition, OnlyRotation, OnlyScale, PositionAndRotation, All }
24 public
enum OnSerializeRigidBody { OnlyVelocity, OnlyAngularVelocity, All }
25
26 ///
<summary>
27 ///
Options to define how Ownership Transfer is handled per PhotonView.
28 ///
</summary>
29 ///
<remarks>
30 ///
This setting affects how RequestOwnership and TransferOwnership work at runtime.
31 ///
</remarks>
32 public
enum OwnershipOption
33 {

34     ///
<summary>
35     ///
Ownership is fixed. Instantiated objects stick with their creator, scene objects always belong to the Master Client.
36     ///
</summary>
37     Fixed,

38     ///
<summary>
39     ///
Ownership can be taken away from the current owner who can't object.
40     ///
</summary>
41     Takeover,

42     ///
<summary>
43     ///
Ownership can be requested with PhotonView.RequestOwnership but the current owner has to agree to give up ownership.
44     ///
</summary>
45     ///
<remarks>The current owner has to implement IPunCallbacks.OnOwnershipRequest to react to the ownership request.</remarks>
46     Request
47 }

48
49
50 ///
<summary>
51 ///
PUN's NetworkView replacement class for networking. Use it like a NetworkView.
52 ///
</summary>
53 ///
\ingroup publicApi
54 [AddComponentMenu(
"Photon Networking/Photon View &v")]
55 public
class PhotonView : Photon.MonoBehaviour
56 {
57     #
if UNITY_EDITOR
58     
[ContextMenu("Open PUN Wizard")]
59     
void OpenPunWizard()
60     {
61         EditorApplication.ExecuteMenuItem(
"Window/Photon Unity Networking");
62     }
63     #endif
64
65     
public int ownerId;
66
67     
public int group = 0;
68
69     
protected internal bool mixedModeIsReliable = false;
70
71     
// NOTE: this is now an integer because unity won't serialize short (needed for instantiation). we SEND only a short though!
72     
// NOTE: prefabs have a prefixBackup of -1. this is replaced with any currentLevelPrefix that's used at runtime. instantiated GOs get their prefix set pre-instantiation (so those are not -1 anymore)
73     
public int prefix
74     {
75         
get
76         {
77             
if (this.prefixBackup == -1 && PhotonNetwork.networkingPeer != null)
78             {
79                 
this.prefixBackup = PhotonNetwork.networkingPeer.currentLevelPrefix;
80             }
81
82             
return this.prefixBackup;
83         }
84         
set { this.prefixBackup = value; }
85     }
86
87     
// this field is serialized by unity. that means it is copied when instantiating a persistent obj into the scene
88     
public int prefixBackup = -1;
89
90     ///
<summary>
91     ///
This is the instantiationData that was passed when calling PhotonNetwork.Instantiate* (if that was used to spawn this prefab)
92     ///
</summary>
93     
public object[] instantiationData
94     {
95         
get
96         {
97             
if (!this.didAwake)
98             {
99                 
// even though viewID and instantiationID are setup before the GO goes live, this data can't be set. as workaround: fetch it if needed
100                 
this.instantiationDataField = PhotonNetwork.networkingPeer.FetchInstantiationData(this.instantiationId);
101             }
102             
return this.instantiationDataField;
103         }
104         
set { this.instantiationDataField = value; }
105     }
106
107     
private object[] instantiationDataField;
108
109     ///
<summary>
110     ///
For internal use only, don't use
111     ///
</summary>
112     
protected internal object[] lastOnSerializeDataSent = null;
113
114     ///
<summary>
115     ///
For internal use only, don't use
116     ///
</summary>
117     
protected internal object[] lastOnSerializeDataReceived = null;
118
119     
public Component observed;
120
121     
public ViewSynchronization synchronization;
122
123     
public OnSerializeTransform onSerializeTransformOption = OnSerializeTransform.PositionAndRotation;
124
125     
public OnSerializeRigidBody onSerializeRigidBodyOption = OnSerializeRigidBody.All;
126
127     ///
<summary>Defines if ownership of this PhotonView is fixed, can be requested or simply taken.</summary>
128     ///
<remarks>
129     ///
Note that you can't edit this value at runtime.
130     ///
The options are described in enum OwnershipOption.
131     ///
The current owner has to implement IPunCallbacks.OnOwnershipRequest to react to the ownership request.
132     ///
</remarks>
133     
public OwnershipOption ownershipTransfer = OwnershipOption.Fixed;
134
135     
public List<Component> ObservedComponents;
136     Dictionary<Component, MethodInfo> m_OnSerializeMethodInfos =
new Dictionary<Component, MethodInfo>();
137
138     
//These fields are only used in the CustomEditor for this script and would trigger a
139     
//"this variable is never used" warning, which I am suppressing here
140 #pragma warning disable
0414
141     
[SerializeField]
142     
bool ObservedComponentsFoldoutOpen = true;
143 #pragma warning restore
0414
144
145     
[SerializeField]
146     
private int viewIdField = 0;
147
148     ///
<summary>
149     ///
The ID of the PhotonView. Identifies it in a networked game (per room).
150     ///
</summary>
151     ///
<remarks>See: [Network Instantiation](@ref instantiateManual)</remarks>
152     
public int viewID
153     {
154         
get { return this.viewIdField; }
155         
set
156         {
157             
// if ID was 0 for an awakened PhotonView, the view should add itself into the networkingPeer.photonViewList after setup
158             
bool viewMustRegister = this.didAwake && this.viewIdField == 0;
159
160             
// TODO: decide if a viewID can be changed once it wasn't 0. most likely that is not a good idea
161             
// check if this view is in networkingPeer.photonViewList and UPDATE said list (so we don't keep the old viewID with a reference to this object)
162             
// PhotonNetwork.networkingPeer.RemovePhotonView(this, true);
163
164             
this.ownerId = value / PhotonNetwork.MAX_VIEW_IDS;
165
166             
this.viewIdField = value;
167
168             
if (viewMustRegister)
169             {
170                 PhotonNetwork.networkingPeer.RegisterPhotonView(
this);
171             }
172             
//Debug.Log("Set viewID: " + value + " -> owner: " + this.ownerId + " subId: " + this.subId);
173         }
174     }
175
176     
public int instantiationId; // if the view was instantiated with a GO, this GO has a instantiationID (first view's viewID)
177
178     ///
<summary>True if the PhotonView was loaded with the scene (game object) or instantiated with InstantiateSceneObject.</summary>
179     ///
<remarks>
180     ///
Scene objects are not owned by a particular player but belong to the scene. Thus they don't get destroyed when their
181     ///
creator leaves the game and the current Master Client can control them (whoever that is).
182     ///
The ownerId is 0 (player IDs are 1 and up).
183     ///
</remarks>
184     
public bool isSceneView
185     {
186         
get { return this.CreatorActorNr == 0; }
187     }

188
189     ///
<summary>
190     ///
The owner of a PhotonView is the player who created the GameObject with that view. Objects in the scene don't have an owner.
191     ///
</summary>
192     ///
<remarks>
193     ///
The owner/controller of a PhotonView is also the client which sends position updates of the GameObject.
194     ///

195     ///
Ownership can be transferred to another player with PhotonView.TransferOwnership or any player can request
196     ///
ownership by calling the PhotonView's RequestOwnership method.
197     ///
The current owner has to implement IPunCallbacks.OnOwnershipRequest to react to the ownership request.
198     ///
</remarks>
199     
public PhotonPlayer owner
200     {
201         
get { return PhotonPlayer.Find(this.ownerId); }
202     }
203
204     
public int OwnerActorNr
205     {
206         
get { return this.ownerId; }
207     }
208
209     
public bool isOwnerActive
210     {
211         
get { return this.ownerId != 0 && PhotonNetwork.networkingPeer.mActors.ContainsKey(this.ownerId); }
212     }
213
214     
public int CreatorActorNr
215     {
216         
get { return this.viewIdField / PhotonNetwork.MAX_VIEW_IDS; }
217     }

218
219     ///
<summary>
220     ///
True if the PhotonView is "mine" and can be controlled by this client.
221     ///
</summary>
222     ///
<remarks>
223     ///
PUN has an ownership concept that defines who can control and destroy each PhotonView.
224     ///
True in case the owner matches the local PhotonPlayer.
225     ///
True if this is a scene photonview on the Master client.
226     ///
</remarks>
227     
public bool isMine
228     {
229         
get
230         {
231             
return (this.ownerId == PhotonNetwork.player.ID) || (!this.isOwnerActive && PhotonNetwork.isMasterClient);
232         }
233     }
234     
235     
protected internal bool didAwake;
236
237     
[SerializeField]
238     
protected internal bool isRuntimeInstantiated;
239
240     
protected internal bool destroyedByPhotonNetworkOrQuit;
241
242     ///
<summary>Called by Unity on start of the application and does a setup the PhotonView.</summary>
243     
protected internal void Awake()
244     {
245         
// registration might be too late when some script (on this GO) searches this view BUT GetPhotonView() can search ALL in that case
246         PhotonNetwork.networkingPeer.RegisterPhotonView(
this);
247
248         
this.instantiationDataField = PhotonNetwork.networkingPeer.FetchInstantiationData(this.instantiationId);
249         
this.didAwake = true;
250     }

251
252     ///
<summary>
253     ///
Depending on the PhotonView's ownershipTransfer setting, any client can request to become owner of the PhotonView.
254     ///
</summary>
255     ///
<remarks>
256     ///
Requesting ownership can give you control over a PhotonView, if the ownershipTransfer setting allows that.
257     ///
The current owner might have to implement IPunCallbacks.OnOwnershipRequest to react to the ownership request.
258     ///

259     ///
The owner/controller of a PhotonView is also the client which sends position updates of the GameObject.
260     ///
</remarks>
261     
public void RequestOwnership()
262     {
263         PhotonNetwork.networkingPeer.RequestOwnership(
this.viewID, this.ownerId);
264     }

265
266     ///
<summary>
267     ///
Transfers the ownership of this PhotonView (and GameObject) to another player.
268     ///
</summary>
269     ///
<remarks>
270     ///
The owner/controller of a PhotonView is also the client which sends position updates of the GameObject.
271     ///
</remarks>
272     
public void TransferOwnership(PhotonPlayer newOwner)
273     {
274         
this.TransferOwnership(newOwner.ID);
275     }

276
277     ///
<summary>
278     ///
Transfers the ownership of this PhotonView (and GameObject) to another player.
279     ///
</summary>
280     ///
<remarks>
281     ///
The owner/controller of a PhotonView is also the client which sends position updates of the GameObject.
282     ///
</remarks>
283     
public void TransferOwnership(int newOwnerId)
284     {
285         PhotonNetwork.networkingPeer.TransferOwnership(
this.viewID, newOwnerId);
286         
this.ownerId = newOwnerId; // immediately switch ownership locally, to avoid more updates sent from this client.
287     }
288
289
290     
protected internal void OnApplicationQuit()
291     {
292         destroyedByPhotonNetworkOrQuit =
true; // on stop-playing its ok Destroy is being called directly (not by PN.Destroy())
293     }
294
295     
protected internal void OnDestroy()
296     {
297         
if (!this.destroyedByPhotonNetworkOrQuit)
298         {
299             PhotonNetwork.networkingPeer.LocalCleanPhotonView(
this);
300         }
301
302         
if (!this.destroyedByPhotonNetworkOrQuit && !Application.isLoadingLevel)
303         {
304             
if (this.instantiationId > 0)
305             {
306                 
// if this viewID was not manually assigned (and we're not shutting down or loading a level), you should use PhotonNetwork.Destroy() to get rid of GOs with PhotonViews
307                 Debug.LogError(
"OnDestroy() seems to be called without PhotonNetwork.Destroy()?! GameObject: " + this.gameObject + " Application.isLoadingLevel: " + Application.isLoadingLevel);
308             }
309             
else
310             {
311                 
// this seems to be a manually instantiated PV. if it's local, we could warn if the ID is not in the allocated-list
312                 
if (this.viewID <= 0)
313                 {
314                     Debug.LogWarning(
string.Format("OnDestroy manually allocated PhotonView {0}. The viewID is 0. Was it ever (manually) set?", this));
315                 }
316                 
else if (this.isMine && !PhotonNetwork.manuallyAllocatedViewIds.Contains(this.viewID))
317                 {
318                     Debug.LogWarning(
string.Format("OnDestroy manually allocated PhotonView {0}. The viewID is local (isMine) but not in manuallyAllocatedViewIds list. Use UnAllocateViewID() after you destroyed the PV.", this));
319                 }
320             }
321         }
322     }
323
324     
private MethodInfo OnSerializeMethodInfo;
325
326     
private bool failedToFindOnSerialize;
327
328     
public void SerializeView( PhotonStream stream, PhotonMessageInfo info )
329     {
330         SerializeComponent( observed, stream, info );
331
332         
for( int i = 0; i < ObservedComponents.Count; ++i )
333         {
334             SerializeComponent( ObservedComponents[ i ], stream, info );
335         }
336     }
337
338     
public void DeserializeView( PhotonStream stream, PhotonMessageInfo info )
339     {
340         DeserializeComponent( observed, stream, info );
341
342         
for( int i = 0; i < ObservedComponents.Count; ++i )
343         {
344             DeserializeComponent( ObservedComponents[ i ], stream, info );
345         }
346     }
347
348     
internal protected void DeserializeComponent( Component component, PhotonStream stream, PhotonMessageInfo info )
349     {
350         
if( component == null )
351         {
352             
return;
353         }
354
355         
// Use incoming data according to observed type
356         
if( component is MonoBehaviour )
357         {
358             ExecuteComponentOnSerialize( component, stream, info );
359         }
360         
else if( component is Transform )
361         {
362             Transform trans = (Transform)component;
363
364             
switch( onSerializeTransformOption )
365             {
366             
case OnSerializeTransform.All:
367                 trans.localPosition = (Vector3)stream.ReceiveNext();
368                 trans.localRotation = (Quaternion)stream.ReceiveNext();
369                 trans.localScale = (Vector3)stream.ReceiveNext();
370                 
break;
371             
case OnSerializeTransform.OnlyPosition:
372                 trans.localPosition = (Vector3)stream.ReceiveNext();
373                 
break;
374             
case OnSerializeTransform.OnlyRotation:
375                 trans.localRotation = (Quaternion)stream.ReceiveNext();
376                 
break;
377             
case OnSerializeTransform.OnlyScale:
378                 trans.localScale = (Vector3)stream.ReceiveNext();
379                 
break;
380             
case OnSerializeTransform.PositionAndRotation:
381                 trans.localPosition = (Vector3)stream.ReceiveNext();
382                 trans.localRotation = (Quaternion)stream.ReceiveNext();
383                 
break;
384             }
385         }
386         
else if( component is Rigidbody )
387         {
388             Rigidbody rigidB = (Rigidbody)component;
389
390             
switch( onSerializeRigidBodyOption )
391             {
392             
case OnSerializeRigidBody.All:
393                 rigidB.velocity = (Vector3)stream.ReceiveNext();
394                 rigidB.angularVelocity = (Vector3)stream.ReceiveNext();
395                 
break;
396             
case OnSerializeRigidBody.OnlyAngularVelocity:
397                 rigidB.angularVelocity = (Vector3)stream.ReceiveNext();
398                 
break;
399             
case OnSerializeRigidBody.OnlyVelocity:
400                 rigidB.velocity = (Vector3)stream.ReceiveNext();
401                 
break;
402             }
403         }
404         
else if( component is Rigidbody2D )
405         {
406             Rigidbody2D rigidB = (Rigidbody2D)component;
407
408             
switch( onSerializeRigidBodyOption )
409             {
410             
case OnSerializeRigidBody.All:
411                 rigidB.velocity = (Vector2)stream.ReceiveNext();
412                 rigidB.angularVelocity = (
float)stream.ReceiveNext();
413                 
break;
414             
case OnSerializeRigidBody.OnlyAngularVelocity:
415                 rigidB.angularVelocity = (
float)stream.ReceiveNext();
416                 
break;
417             
case OnSerializeRigidBody.OnlyVelocity:
418                 rigidB.velocity = (Vector2)stream.ReceiveNext();
419                 
break;
420             }
421         }
422         
else
423         {
424             Debug.LogError(
"Type of observed is unknown when receiving." );
425         }
426     }
427
428     
internal protected void SerializeComponent( Component component, PhotonStream stream, PhotonMessageInfo info )
429     {
430         
if( component == null )
431         {
432             
return;
433         }
434
435         
if( component is MonoBehaviour )
436         {
437             ExecuteComponentOnSerialize( component, stream, info );
438         }
439         
else if( component is Transform )
440         {
441             Transform trans = (Transform)component;
442
443             
switch( onSerializeTransformOption )
444             {
445             
case OnSerializeTransform.All:
446                 stream.SendNext( trans.localPosition );
447                 stream.SendNext( trans.localRotation );
448                 stream.SendNext( trans.localScale );
449                 
break;
450             
case OnSerializeTransform.OnlyPosition:
451                 stream.SendNext( trans.localPosition );
452                 
break;
453             
case OnSerializeTransform.OnlyRotation:
454                 stream.SendNext( trans.localRotation );
455                 
break;
456             
case OnSerializeTransform.OnlyScale:
457                 stream.SendNext( trans.localScale );
458                 
break;
459             
case OnSerializeTransform.PositionAndRotation:
460                 stream.SendNext( trans.localPosition );
461                 stream.SendNext( trans.localRotation );
462                 
break;
463             }
464         }
465         
else if( component is Rigidbody )
466         {
467             Rigidbody rigidB = (Rigidbody)component;
468
469             
switch( onSerializeRigidBodyOption )
470             {
471             
case OnSerializeRigidBody.All:
472                 stream.SendNext( rigidB.velocity );
473                 stream.SendNext( rigidB.angularVelocity );
474                 
break;
475             
case OnSerializeRigidBody.OnlyAngularVelocity:
476                 stream.SendNext( rigidB.angularVelocity );
477                 
break;
478             
case OnSerializeRigidBody.OnlyVelocity:
479                 stream.SendNext( rigidB.velocity );
480                 
break;
481             }
482         }
483         
else if( component is Rigidbody2D )
484         {
485             Rigidbody2D rigidB = (Rigidbody2D)component;
486
487             
switch( onSerializeRigidBodyOption )
488             {
489             
case OnSerializeRigidBody.All:
490                 stream.SendNext( rigidB.velocity );
491                 stream.SendNext( rigidB.angularVelocity );
492                 
break;
493             
case OnSerializeRigidBody.OnlyAngularVelocity:
494                 stream.SendNext( rigidB.angularVelocity );
495                 
break;
496             
case OnSerializeRigidBody.OnlyVelocity:
497                 stream.SendNext( rigidB.velocity );
498                 
break;
499             }
500         }
501         
else
502         {
503             Debug.LogError(
"Observed type is not serializable: " + component.GetType() );
504         }
505     }
506
507     
internal protected void ExecuteComponentOnSerialize( Component component, PhotonStream stream, PhotonMessageInfo info )
508     {
509         
if( component != null )
510         {
511             
if( m_OnSerializeMethodInfos.ContainsKey( component ) == false )
512             {
513                 MethodInfo newMethod =
null;
514                 
bool foundMethod = NetworkingPeer.GetMethod( component as MonoBehaviour, PhotonNetworkingMessage.OnPhotonSerializeView.ToString(), out newMethod );
515
516                 
if( foundMethod == false )
517                 {
518                     Debug.LogError(
"The observed monobehaviour (" + component.name + ") of this PhotonView does not implement OnPhotonSerializeView()!" );
519                     newMethod =
null;
520                 }
521
522                 m_OnSerializeMethodInfos.Add( component, newMethod );
523             }
524
525             
if( m_OnSerializeMethodInfos[ component ] != null )
526             {
527                 m_OnSerializeMethodInfos[ component ].Invoke( component,
new object[] { stream, info } );
528             }
529         }
530     }

531
532     ///
<summary>
533     ///
Call a RPC method of this GameObject on remote clients of this room (or on all, inclunding this client).
534     ///
</summary>
535     ///
<remarks>
536     ///
[Remote Procedure Calls](@ref rpcManual) are an essential tool in making multiplayer games with PUN.
537     ///
It enables you to make every client in a room call a specific method.
538     ///
539     ///
RPC calls can target "All" or the "Others".
540     ///
Usually, the target "All" gets executed locally immediately after sending the RPC.
541     ///
The "*ViaServer" options send the RPC to the server and execute it on this client when it's sent back.
542     ///
Of course, calls are affected by this client's lag and that of remote clients.
543     ///
544     ///
Each call automatically is routed to the same PhotonView (and GameObject) that was used on the
545     ///
originating client.
546     ///
547     ///
See: [Remote Procedure Calls](@ref rpcManual).
548     ///
</remarks>
549     ///
<param name="methodName">The name of a fitting method that was has the RPC attribute.</param>
550     ///
<param name="target">The group of targets and the way the RPC gets sent.</param>
551     ///
<param name="parameters">The parameters that the RPC method has (must fit this call!).</param>
552     
public void RPC(string methodName, PhotonTargets target, params object[] parameters)
553     {
554         RpcSecure(methodName, target,
false, parameters);
555     }

556
557     ///
<summary>
558     ///
Call a RPC method of this GameObject on remote clients of this room (or on all, inclunding this client).
559     ///
</summary>
560     ///
<remarks>
561     ///
[Remote Procedure Calls](@ref rpcManual) are an essential tool in making multiplayer games with PUN.
562     ///
It enables you to make every client in a room call a specific method.
563     ///
564     ///
RPC calls can target "All" or the "Others".
565     ///
Usually, the target "All" gets executed locally immediately after sending the RPC.
566     ///
The "*ViaServer" options send the RPC to the server and execute it on this client when it's sent back.
567     ///
Of course, calls are affected by this client's lag and that of remote clients.
568     ///
569     ///
Each call automatically is routed to the same PhotonView (and GameObject) that was used on the
570     ///
originating client.
571     ///
572     ///
See: [Remote Procedure Calls](@ref rpcManual).
573     ///
</remarks>
574     ///<param name="methodName">
The name of a fitting method that was has the RPC attribute.</param>
575     ///<param name="target">
The group of targets and the way the RPC gets sent.</param>
576     ///<param name="encrypt">
</param>
577     ///<param name="parameters">
The parameters that the RPC method has (must fit this call!).</param>
578     
public void RpcSecure(string methodName, PhotonTargets target, bool encrypt, params object[] parameters)
579     {
580         
if(PhotonNetwork.networkingPeer.hasSwitchedMC && target == PhotonTargets.MasterClient)
581         {
582             PhotonNetwork.RPC(
this, methodName, PhotonNetwork.masterClient, encrypt, parameters);
583         }
584         
else
585         {
586             PhotonNetwork.RPC(
this, methodName, target, encrypt, parameters);
587         }
588     }

589
590     ///
<summary>
591     ///
Call a RPC method of this GameObject on remote clients of this room (or on all, inclunding this client).
592     ///
</summary>
593     ///
<remarks>
594     ///
[Remote Procedure Calls](@ref rpcManual) are an essential tool in making multiplayer games with PUN.
595     ///
It enables you to make every client in a room call a specific method.
596     ///
597     ///
This method allows you to make an RPC calls on a specific player's client.
598     ///
Of course, calls are affected by this client's lag and that of remote clients.
599     ///
600     ///
Each call automatically is routed to the same PhotonView (and GameObject) that was used on the
601     ///
originating client.
602     ///
603     ///
See: [Remote Procedure Calls](@ref rpcManual).
604     ///
</remarks>
605     ///
<param name="methodName">The name of a fitting method that was has the RPC attribute.</param>
606     ///
<param name="targetPlayer">The group of targets and the way the RPC gets sent.</param>
607     ///
<param name="parameters">The parameters that the RPC method has (must fit this call!).</param>
608     
public void RPC(string methodName, PhotonPlayer targetPlayer, params object[] parameters)
609     {
610         PhotonNetwork.RPC(
this, methodName, targetPlayer, false, parameters);
611     }

612
613     ///
<summary>
614     ///
Call a RPC method of this GameObject on remote clients of this room (or on all, inclunding this client).
615     ///
</summary>
616     ///
<remarks>
617     ///
[Remote Procedure Calls](@ref rpcManual) are an essential tool in making multiplayer games with PUN.
618     ///
It enables you to make every client in a room call a specific method.
619     ///
620     ///
This method allows you to make an RPC calls on a specific player's client.
621     ///
Of course, calls are affected by this client's lag and that of remote clients.
622     ///
623     ///
Each call automatically is routed to the same PhotonView (and GameObject) that was used on the
624     ///
originating client.
625     ///
626     ///
See: [Remote Procedure Calls](@ref rpcManual).
627     ///
</remarks>
628     ///<param name="methodName">
The name of a fitting method that was has the RPC attribute.</param>
629     ///<param name="targetPlayer">
The group of targets and the way the RPC gets sent.</param>
630     ///<param name="encrypt">
</param>
631     ///<param name="parameters">
The parameters that the RPC method has (must fit this call!).</param>
632     
public void RpcSecure(string methodName, PhotonPlayer targetPlayer, bool encrypt, params object[] parameters)
633     {
634         PhotonNetwork.RPC(
this, methodName, targetPlayer, encrypt, parameters);
635     }
636
637     
public static PhotonView Get(Component component)
638     {
639         
return component.GetComponent<PhotonView>();
640     }
641
642     
public static PhotonView Get(GameObject gameObj)
643     {
644         
return gameObj.GetComponent<PhotonView>();
645     }
646
647     
public static PhotonView Find(int viewID)
648     {
649         
return PhotonNetwork.networkingPeer.GetPhotonView(viewID);
650     }
651
652     
public override string ToString()
653     {
654         
return string.Format("View ({3}){0} on {1} {2}", this.viewID, (this.gameObject != null) ? this.gameObject.name : "GO==null", (this.isSceneView) ? "(scene)" : string.Empty, this.prefix);
655     }
656 }


----------------------------------------------------------------------------

PhotonNetwork Framework for Unity - Copyright (C) 2011 Exit Games GmbH

developer@exitgames.com

----------------------------------------------------------------------------

Options to define how Ownership Transfer is handled per PhotonView.

This setting affects how RequestOwnership and TransferOwnership work at runtime.

Ownership is fixed. Instantiated objects stick with their creator, scene objects always belong to the Master Client.

Ownership can be taken away from the current owner who can't object.

Ownership can be requested with PhotonView.RequestOwnership but the current owner has to agree to give up ownership.

The current owner has to implement IPunCallbacks.OnOwnershipRequest to react to the ownership request.

PUN's NetworkView replacement class for networking. Use it like a NetworkView.

\ingroup publicApi

NOTE: this is now an integer because unity won't serialize short (needed for instantiation). we SEND only a short though!

NOTE: prefabs have a prefixBackup of -1. this is replaced with any currentLevelPrefix that's used at runtime. instantiated GOs get their prefix set pre-instantiation (so those are not -1 anymore)

this field is serialized by unity. that means it is copied when instantiating a persistent obj into the scene

This is the instantiationData that was passed when calling PhotonNetwork.Instantiate* (if that was used to spawn this prefab)

even though viewID and instantiationID are setup before the GO goes live, this data can't be set. as workaround: fetch it if needed

For internal use only, don't use

For internal use only, don't use

Defines if ownership of this PhotonView is fixed, can be requested or simply taken.

Note that you can't edit this value at runtime.

The options are described in enum OwnershipOption.

The current owner has to implement IPunCallbacks.OnOwnershipRequest to react to the ownership request.

These fields are only used in the CustomEditor for this script and would trigger a

"this variable is never used" warning, which I am suppressing here

The ID of the PhotonView. Identifies it in a networked game (per room).

See: [Network Instantiation](@ref instantiateManual)

if ID was 0 for an awakened PhotonView, the view should add itself into the networkingPeer.photonViewList after setup

TODO: decide if a viewID can be changed once it wasn't 0. most likely that is not a good idea

check if this view is in networkingPeer.photonViewList and UPDATE said list (so we don't keep the old viewID with a reference to this object)

PhotonNetwork.networkingPeer.RemovePhotonView(this, true);

Debug.Log("Set viewID: " + value + " -> owner: " + this.ownerId + " subId: " + this.subId);

public int instantiationId; if the view was instantiated with a GO, this GO has a instantiationID (first view's viewID)

True if the PhotonView was loaded with the scene (game object) or instantiated with InstantiateSceneObject.

Scene objects are not owned by a particular player but belong to the scene. Thus they don't get destroyed when their

creator leaves the game and the current Master Client can control them (whoever that is).

The ownerId is 0 (player IDs are 1 and up).

The owner of a PhotonView is the player who created the GameObject with that view. Objects in the scene don't have an owner.

The ownercontroller of a PhotonView is also the client which sends position updates of the GameObject.

Ownership can be transferred to another player with PhotonView.TransferOwnership or any player can request

ownership by calling the PhotonView's RequestOwnership method.

The current owner has to implement IPunCallbacks.OnOwnershipRequest to react to the ownership request.

True if the PhotonView is "mine" and can be controlled by this client.

PUN has an ownership concept that defines who can control and destroy each PhotonView.

True in case the owner matches the local PhotonPlayer.

True if this is a scene photonview on the Master client.

Called by Unity on start of the application and does a setup the PhotonView.

registration might be too late when some script (on this GO) searches this view BUT GetPhotonView() can search ALL in that case

Depending on the PhotonView's ownershipTransfer setting, any client can request to become owner of the PhotonView.

Requesting ownership can give you control over a PhotonView, if the ownershipTransfer setting allows that.

The current owner might have to implement IPunCallbacks.OnOwnershipRequest to react to the ownership request.

The ownercontroller of a PhotonView is also the client which sends position updates of the GameObject.

Transfers the ownership of this PhotonView (and GameObject) to another player.

The ownercontroller of a PhotonView is also the client which sends position updates of the GameObject.

Transfers the ownership of this PhotonView (and GameObject) to another player.

The ownercontroller of a PhotonView is also the client which sends position updates of the GameObject.

this.ownerId = newOwnerId; immediately switch ownership locally, to avoid more updates sent from this client.

destroyedByPhotonNetworkOrQuit = true; on stop-playing its ok Destroy is being called directly (not by PN.Destroy())

if this viewID was not manually assigned (and we're not shutting down or loading a level), you should use PhotonNetwork.Destroy() to get rid of GOs with PhotonViews

this seems to be a manually instantiated PV. if it's local, we could warn if the ID is not in the allocated-list

Use incoming data according to observed type

Call a RPC method of this GameObject on remote clients of this room (or on all, inclunding this client).

[Remote Procedure Calls](@ref rpcManual) are an essential tool in making multiplayer games with PUN.

It enables you to make every client in a room call a specific method.

RPC calls can target "All" or the "Others".

Usually, the target "All" gets executed locally immediately after sending the RPC.

The "*ViaServer" options send the RPC to the server and execute it on this client when it's sent back.

Of course, calls are affected by this client's lag and that of remote clients.

Each call automatically is routed to the same PhotonView (and GameObject) that was used on the

originating client.

See: [Remote Procedure Calls](@ref rpcManual).

The name of a fitting method that was has the RPC attribute.

The group of targets and the way the RPC gets sent.

The parameters that the RPC method has (must fit this call!).

Call a RPC method of this GameObject on remote clients of this room (or on all, inclunding this client).

[Remote Procedure Calls](@ref rpcManual) are an essential tool in making multiplayer games with PUN.

It enables you to make every client in a room call a specific method.

RPC calls can target "All" or the "Others".

Usually, the target "All" gets executed locally immediately after sending the RPC.

The "*ViaServer" options send the RPC to the server and execute it on this client when it's sent back.

Of course, calls are affected by this client's lag and that of remote clients.

Each call automatically is routed to the same PhotonView (and GameObject) that was used on the

originating client.

See: [Remote Procedure Calls](@ref rpcManual).

The name of a fitting method that was has the RPC attribute.

The group of targets and the way the RPC gets sent.

The parameters that the RPC method has (must fit this call!).

Call a RPC method of this GameObject on remote clients of this room (or on all, inclunding this client).

[Remote Procedure Calls](@ref rpcManual) are an essential tool in making multiplayer games with PUN.

It enables you to make every client in a room call a specific method.

This method allows you to make an RPC calls on a specific player's client.

Of course, calls are affected by this client's lag and that of remote clients.

Each call automatically is routed to the same PhotonView (and GameObject) that was used on the

originating client.

See: [Remote Procedure Calls](@ref rpcManual).

The name of a fitting method that was has the RPC attribute.

The group of targets and the way the RPC gets sent.

The parameters that the RPC method has (must fit this call!).

Call a RPC method of this GameObject on remote clients of this room (or on all, inclunding this client).

[Remote Procedure Calls](@ref rpcManual) are an essential tool in making multiplayer games with PUN.

It enables you to make every client in a room call a specific method.

This method allows you to make an RPC calls on a specific player's client.

Of course, calls are affected by this client's lag and that of remote clients.

Each call automatically is routed to the same PhotonView (and GameObject) that was used on the

originating client.

See: [Remote Procedure Calls](@ref rpcManual).

The name of a fitting method that was has the RPC attribute.

The group of targets and the way the RPC gets sent.

The parameters that the RPC method has (must fit this call!).




Trò chơi Tic-Tac-Toe, game đánh caro full source code 53.588 lượt xem

Gõ tìm kiếm nhanh...